using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace DocumentCreationSystem.Services
{
    /// <summary>
    /// RWKV 模型下载进度
    /// </summary>
    public class RWKVDownloadProgress
    {
        public long Total { get; set; }
        public long Completed { get; set; }
        public double Percent => Total > 0 ? (double)Completed / Total * 100 : 0.0;
        public string Status { get; set; } = string.Empty;
        public bool IsCompleted { get; set; }
        public bool IsError { get; set; }
        public string? ErrorMessage { get; set; }
    }

    /// <summary>
    /// RWKV 模型下载与 SHA256 校验服务
    /// </summary>
    public class RWKVModelDownloadService
    {
        private readonly ILogger<RWKVModelDownloadService> _logger;
        private readonly HttpClient _httpClient;

        public RWKVModelDownloadService(ILogger<RWKVModelDownloadService> logger, HttpClient httpClient)
        {
            _logger = logger;
            _httpClient = httpClient;
            _httpClient.Timeout = TimeSpan.FromMinutes(30);
        }

        /// <summary>
        /// 下载模型到目标路径（支持取消），并可选进行 sha256 校验
        /// </summary>
        public async Task<bool> DownloadAsync(
            string url,
            string destFile,
            IProgress<RWKVDownloadProgress>? progress = null,
            string? expectedSha256 = null,
            CancellationToken ct = default)
        {
            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(destFile)!);

                using var req = new HttpRequestMessage(HttpMethod.Get, url);
                using var resp = await _httpClient.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, ct);
                resp.EnsureSuccessStatusCode();

                var total = resp.Content.Headers.ContentLength ?? 0;
                await using var input = await resp.Content.ReadAsStreamAsync(ct);
                var tmp = destFile + ".part";
                await using var output = File.Open(tmp, FileMode.Create, FileAccess.Write, FileShare.None);

                var rented = ArrayPool<byte>.Shared.Rent(1024 * 128);
                try
                {
                    var buffer = rented;
                    long completed = 0;
                    int read;
                    Report(progress, new RWKVDownloadProgress { Total = total, Completed = 0, Status = "开始下载" });
                    while ((read = await input.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
                    {
                        await output.WriteAsync(buffer, 0, read, ct);
                        completed += read;
                        Report(progress, new RWKVDownloadProgress { Total = total, Completed = completed, Status = "下载中" });
                    }
                }
                finally
                {
                    ArrayPool<byte>.Shared.Return(rented);
                }

                await output.FlushAsync(ct);

                // 校验 SHA256
                if (!string.IsNullOrWhiteSpace(expectedSha256))
                {
                    var ok = await VerifySha256Async(tmp, expectedSha256, ct);
                    if (!ok)
                    {
                        File.Delete(tmp);
                        Report(progress, new RWKVDownloadProgress { Total = total, Completed = total, Status = "校验失败", IsError = true, ErrorMessage = "SHA256 不匹配" });
                        return false;
                    }
                }

                // 原子移动
                if (File.Exists(destFile)) File.Delete(destFile);
                File.Move(tmp, destFile);

                Report(progress, new RWKVDownloadProgress { Total = total, Completed = total, Status = "完成", IsCompleted = true });
                return true;
            }
            catch (OperationCanceledException)
            {
                Report(progress, new RWKVDownloadProgress { Status = "已取消", IsError = true });
                return false;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "下载模型失败: {Url}", url);
                Report(progress, new RWKVDownloadProgress { Status = "错误", IsError = true, ErrorMessage = ex.Message });
                return false;
            }
        }

        private static void Report(IProgress<RWKVDownloadProgress>? p, RWKVDownloadProgress v) => p?.Report(v);

        private static async Task<bool> VerifySha256Async(string file, string expected, CancellationToken ct)
        {
            expected = expected.Trim().ToLowerInvariant();
            await using var fs = File.OpenRead(file);
            using var sha = SHA256.Create();
            var hash = await sha.ComputeHashAsync(fs, ct);
            var hex = Convert.ToHexString(hash).ToLowerInvariant();
            return hex == expected;
        }
    }
}

